package loveqq.niceexcel.read.handler.internal;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import loveqq.niceexcel.annotation.ExcelHead;
import loveqq.niceexcel.annotation.format.DateTimeFormat;
import loveqq.niceexcel.annotation.format.NumberFormat;
import loveqq.niceexcel.annotation.internal.Internal;
import loveqq.niceexcel.converter.internal.AutoConverter;
import loveqq.niceexcel.core.LocateDataHeadMetas;
import loveqq.niceexcel.core.MergedRegions;
import loveqq.niceexcel.core.metadata.CellHeadMeta;
import loveqq.niceexcel.core.metadata.DateTimeFormatData;
import loveqq.niceexcel.core.metadata.NumberFormatData;
import loveqq.niceexcel.core.metadata.PositionData;
import loveqq.niceexcel.enums.DataScopeEnum;
import loveqq.niceexcel.enums.DirectionEnum;
import loveqq.niceexcel.read.ReadContext;
import loveqq.niceexcel.read.handler.CellReadHandler;
import loveqq.niceexcel.read.handler.LocateDataReadHandler;
import loveqq.niceexcel.read.handler.RowReadHandler;
import loveqq.niceexcel.read.handler.WorkbookReadHandler;
import loveqq.niceexcel.util.CellUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhongjh@tsintergy.com
 * @date 2022-08-18
 */
@Internal
public class ExcelHeadReadHandler<T> implements WorkbookReadHandler, RowReadHandler, CellReadHandler, LocateDataReadHandler {
    private final Map<String, List<CellHeadMeta>> headMetaCache = new HashMap<>();
    private DirectionEnum parseDirection;

    @Override
    public void onWorkbookBegin(ReadContext context, Workbook workbook) {
        // 初始化表头元数据
        for (Field field : ReflectUtil.getFields(context.getHeadClass())) {
            field.setAccessible(true);
            // 时间格式
            DateTimeFormatData dateTimeFormat = DateTimeFormatData.build(field.getAnnotation(DateTimeFormat.class));
            // 数字格式
            NumberFormatData numberFormat = NumberFormatData.build(field.getAnnotation(NumberFormat.class));
            // 表头
            for (ExcelHead headAnno : field.getAnnotationsByType(ExcelHead.class)) {
                String rowHead = headAnno.row();
                String columnHead = headAnno.column();

                CellHeadMeta headMeta = new CellHeadMeta();
                headMeta.setField(field);
                headMeta.setRowHead(rowHead);
                headMeta.setColumnHead(columnHead);
                if (AutoConverter.class != headAnno.converter()) {
                    headMeta.setConverter(ReflectUtil.newInstance(headAnno.converter()));
                }
                headMeta.setRowPosition(PositionData.build(headAnno.rowPosition()));
                headMeta.setColumnPosition(PositionData.build(headAnno.columnPosition()));
                headMeta.setDateTimeFormat(dateTimeFormat);
                headMeta.setNumberFormat(numberFormat);

                if (StrUtil.isNotEmpty(rowHead)) {
                    this.headMetaCache.computeIfAbsent(rowHead, k -> new ArrayList<>()).add(headMeta);
                }
                if (StrUtil.isNotEmpty(columnHead)) {
                    this.headMetaCache.computeIfAbsent(columnHead, k -> new ArrayList<>()).add(headMeta);
                }
            }
        }
    }

    @Override
    public void onCellRead(ReadContext context, Cell cell) {
        if (!context.getMergedRegions().isRegionFirstCell(cell)) {
            return;
        }
        // 如果是表头名字且是合并区域的第一个单元格, 解析设置定位表头
        String headName = CellUtils.getCellData(context.getMergedRegions().getRegionFirstCell(cell)).getStringValue();
        if (StrUtil.isNotEmpty(headName) && headMetaCache.containsKey(headName)) {
            parseLocateDataHeadMeta(headName, context, cell);
        }
    }

    @Override
    public boolean beforeLocateData(ReadContext context, Cell cell) {
        // 如果是表头, 跳过定位单元格
        String headName = CellUtils.getCellData(context.getMergedRegions().getRegionFirstCell(cell)).getStringValue();
        return StrUtil.isEmpty(headName) || !headMetaCache.containsKey(headName);
    }

    @Override
    public boolean onLocatedDataBegin(ReadContext context, Cell cell, CellHeadMeta locateDataHeadMeta) {
        MergedRegions.Region cellRegion = context.getMergedRegions().getRegion(cell);
        PositionData rowPosition = locateDataHeadMeta.getRowPosition();
        PositionData columnPosition = locateDataHeadMeta.getColumnPosition();
        // 横向逻辑分块
        if (rowPosition.getSize() > 1) {
            int size = 0;
            int index = 0;
            MergedRegions.Region headRegion = locateDataHeadMeta.getRegion();
            for (int i = headRegion.getFirstRow(); i <= headRegion.getLastRow(); i++) {
                MergedRegions.Region region = context.getMergedRegions().getRegion(cell.getRow().getCell(i));
                size++;
                if (cellRegion.getFirstRow() <= i && i <= cellRegion.getLastRow()) {
                    index = size;
                }
                i += (region.getLastRow() - region.getFirstRow());
            }
            if (index != rowPosition.getIndex() || size != rowPosition.getSize()) {
                return false;
            }
        }
        // 竖向逻辑分块
        if (columnPosition.getSize() > 1) {
            int size = 0;
            int index = 0;
            MergedRegions.Region headRegion = locateDataHeadMeta.getRegion();
            for (int i = headRegion.getFirstColumn(); i <= headRegion.getLastColumn(); i++) {
                MergedRegions.Region region = context.getMergedRegions().getRegion(cell.getRow().getCell(i));
                size++;
                if (cellRegion.getFirstColumn() <= i && i <= cellRegion.getLastColumn()) {
                    index = size;
                }
                i += (region.getLastColumn() - region.getFirstColumn());
            }
            if (index != columnPosition.getIndex() || size != columnPosition.getSize()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void onRowEnd(ReadContext context, Row row) {
        if (DirectionEnum.HORIZONTAL == parseDirection) {
            // 单行横向清除表头, 防止下行重复读取
            context.getLocateDataHeadMetas().clearAndResetAllIndex();
            parseDirection = null;
        } else if (DirectionEnum.ALL == parseDirection) {
            // 保留列表头, 下行解析确认行表头才定位数据
            context.getLocateDataHeadMetas().clearAndResetRowIndex();
            parseDirection = null;
        }
    }

    private void parseLocateDataHeadMeta(String headName, ReadContext context, Cell cell) {
        LocateDataHeadMetas locateDataHeadMetas = context.getLocateDataHeadMetas();
        for (CellHeadMeta cellHeadMeta : headMetaCache.get(headName)) {
            cellHeadMeta.setRegion(context.getMergedRegions().getRegion(cell));
            int rowOffset = cellHeadMeta.getRowPosition().getIndex() - 1;
            int columnOffset = cellHeadMeta.getColumnPosition().getIndex() - 1;
            // 横
            if (cellHeadMeta.isHorizontalDirection()) {
                cellHeadMeta.setRowIndex(cell.getRowIndex() + rowOffset);
                cellHeadMeta.setColumnIndex(cell.getColumnIndex() + context.getMergedRegions().getWidth(cell) + columnOffset);
                // 单行一个字段解析
                if (DirectionEnum.HORIZONTAL != parseDirection && !locateDataHeadMetas.isEmpty()) {
                    locateDataHeadMetas.clearAndResetAllIndex();
                    parseDirection = null;
                }
                if (cellHeadMeta.getRowIndex() >= 0 && cellHeadMeta.getColumnIndex() >= 0) {
                    // 只解析一个字段数据, 所以清除所有定位表头
                    locateDataHeadMetas.clearAndResetAllIndex();
                    locateDataHeadMetas.put(cellHeadMeta);
                    parseDirection = DirectionEnum.HORIZONTAL;
                    context.setDataScope(DataScopeEnum.COMMON);
                }
            }
            // 竖
            else if (cellHeadMeta.isVerticalDirection()) {
                cellHeadMeta.setRowIndex(-1);
                cellHeadMeta.setColumnIndex(cell.getColumnIndex() + columnOffset);
                // 多行多个字段解析
                if (DirectionEnum.VERTICAL != parseDirection && !locateDataHeadMetas.isEmpty()) {
                    locateDataHeadMetas.clearAndResetAllIndex();
                    parseDirection = null;
                }
                if (cellHeadMeta.getColumnIndex() >= 0) {
                    locateDataHeadMetas.put(cellHeadMeta);
                    parseDirection = DirectionEnum.VERTICAL;
                }
            }
            // 横竖
            else if (cellHeadMeta.isAllDirection()) {
                if (headName.equals(cellHeadMeta.getRowHead())) {
                    cellHeadMeta.setRowIndex(cell.getRowIndex() + rowOffset);
                } else if (headName.equals(cellHeadMeta.getColumnHead())) {
                    cellHeadMeta.setColumnIndex(cell.getColumnIndex() + columnOffset);
                } else {
                    cellHeadMeta.setRowIndex(-1);
                    cellHeadMeta.setColumnIndex(-1);
                }
                // 单行多个字段解析
                if (DirectionEnum.ALL != parseDirection && !locateDataHeadMetas.isEmpty() && cell.getRowIndex() == cellHeadMeta.getRowIndex()) {
                    locateDataHeadMetas.clearAndResetRowIndex();
                    parseDirection = null;
                }
                if (cellHeadMeta.getRowIndex() >= 0 && cellHeadMeta.getColumnIndex() >= 0) {
                    locateDataHeadMetas.put(cellHeadMeta);
                    parseDirection = DirectionEnum.ALL;
                }
            }
        }
    }

}
